package com.lzq.mybatis.executor;
import com.lzq.mybatis.conf.Configuration;
import com.lzq.mybatis.conf.MappedStatement;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class DefaultExecutor implements Executor{
    private Configuration conf;
    public DefaultExecutor(Configuration configuration) {
        this.conf = configuration;
    }

    public <E> List<E> query(MappedStatement ms, Object parameters) {
        System.out.println(ms.getSql());
        //返回结果
        List<E> res = new ArrayList<E>();
        try{
            //加载驱动
            Class.forName(conf.getJdbcDriver());
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        Connection connection = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        try{
            //获取Connection连接，从conf中获取连接的信息。
            connection = DriverManager.getConnection(conf.getJdbcUrl(),conf.getUserName(),conf.getPassWord());
            //创建preparestatement信息，从mapperstatement中获取sql语句信息。
            preparedStatement = connection.prepareStatement(ms.getSql());
            //设置parameter
            handleParameters(preparedStatement,parameters);
            //执行sql获取resultSet
            resultSet = preparedStatement.executeQuery();

            Class domainClass = Class.forName(ms.getResultType());
            while (resultSet.next()) {
                //实例化要封装的实体类对象
                E obj = (E) domainClass.newInstance();
                //取出结果集的元信息：ResultSetMetaData
                ResultSetMetaData rsmd = resultSet.getMetaData();
                //取出总列数
                int columnCount = rsmd.getColumnCount();
                //遍历总列数
                for (int i = 1; i <= columnCount; i++) {
                    //获取每列的名称，列名的序号是从1开始的
                    String columnName = rsmd.getColumnName(i);
                    //根据得到列名，获取每列的值
                    Object columnValue = resultSet.getObject(columnName);
                    //给obj赋值：使用Java内省机制（借助PropertyDescriptor实现属性的封装）
                    //要求：实体类的属性和数据库表的列名保持一种
                    PropertyDescriptor pd = new PropertyDescriptor(columnName, domainClass);
                    //获取它的写入方法
                    Method writeMethod = pd.getWriteMethod();
                    //把获取的列的值，给对象赋值
                    writeMethod.invoke(obj, columnValue);
                }
                //把赋好值的对象加入到集合中
                res.add(obj);
            }
        }catch (Exception e){
            throw new RuntimeException(e);
        }finally {
            try{
                resultSet.close();
                preparedStatement.close();
                connection.close();
            }catch (SQLException e){
                e.printStackTrace();
            }
        }
        return res;
    }

    //处理parameters
    public void handleParameters(PreparedStatement preparedStatement,Object parameter) throws SQLException {
        if(parameter instanceof Integer){
            preparedStatement.setInt(1, (Integer) parameter);
        }else if(parameter instanceof Long){
            preparedStatement.setLong(1, (Long) parameter);
        }else if(parameter instanceof String){
            preparedStatement.setString(1, (String) parameter);
        }
    }
}
